package com.hundun.vision.biz.core;

import org.ta4j.core.BarSeries;
import org.ta4j.core.Rule;
import org.ta4j.core.indicators.SMAIndicator;
import org.ta4j.core.indicators.bollinger.BollingerBandsLowerIndicator;
import org.ta4j.core.indicators.bollinger.BollingerBandsMiddleIndicator;
import org.ta4j.core.indicators.bollinger.BollingerBandsUpperIndicator;
import org.ta4j.core.indicators.helpers.ClosePriceIndicator;
import org.ta4j.core.indicators.statistics.StandardDeviationIndicator;
import org.ta4j.core.num.DecimalNum;
import org.ta4j.core.rules.OverIndicatorRule;
import org.ta4j.core.rules.StopLossRule;
import org.ta4j.core.rules.UnderIndicatorRule;

import java.math.BigDecimal;

import static java.math.RoundingMode.DOWN;

/**
 * @author ：RuoChen
 * @date ：14:10 2024/2/27
 * @description：布林带多单策略
 */
public class BollingerBandStrategy {
    private static final String name = "布林带空单策略";

    /**
     * 构建交易策略
     *
     * @param barSeries
     * @param priceStep
     * @return
     */
    public static ContractStrategy buildStrategy(BarSeries barSeries, BigDecimal priceStep) {
        // 获取收盘价
        ClosePriceIndicator closePrice = new ClosePriceIndicator(barSeries);
        // 计算布林带
        int bbPeriod = 20;
        SMAIndicator sma = new SMAIndicator(closePrice, bbPeriod);
        StandardDeviationIndicator stdDev = new StandardDeviationIndicator(closePrice, bbPeriod);
        BollingerBandsMiddleIndicator middleBrand = new BollingerBandsMiddleIndicator(sma);
        // 计算布林带上下轨
        BollingerBandsUpperIndicator upperBand = new BollingerBandsUpperIndicator(middleBrand, stdDev);
        BollingerBandsLowerIndicator lowerBand = new BollingerBandsLowerIndicator(middleBrand, stdDev);

        // 计算布林带的上轨和下轨
        BigDecimal upperBandValue = upperBand.getValue(barSeries.getEndIndex()).bigDecimalValue().setScale(6, DOWN);
        BigDecimal lowerBandValue = lowerBand.getValue(barSeries.getEndIndex()).bigDecimalValue().setScale(6, DOWN);
        // 布林带宽度
        BigDecimal bandWidth = upperBandValue.subtract(lowerBandValue);

        // 根据布林带上下轨计算买入和卖出价格
        // 卖出价格
        BigDecimal sellPrice = upperBandValue.add(bandWidth.multiply(priceStep)).setScale(6, DOWN);
        // 买入价格
        BigDecimal buyPrice = lowerBandValue.subtract(bandWidth.multiply(priceStep)).setScale(6, DOWN);

        // 当前价格大于卖出价格：卖出（空单建仓）
        Rule sellRule = new OverIndicatorRule(closePrice, sellPrice);
        // 当前价格小于买入价格：买入（多单建仓）
        Rule buyRule = new UnderIndicatorRule(closePrice, buyPrice);
        // 当前价格小于布林带下线：买入（空单止盈）
        Rule takeSellProfitRule = new UnderIndicatorRule(closePrice, lowerBand);
        // 当前价格大于布林带上线：卖出（多单止盈）
        Rule takeBuyProfitRule = new OverIndicatorRule(closePrice, upperBand);
        StopLossRule buyStopLossRule = new StopLossRule(closePrice, DecimalNum.valueOf("2"));
        StopLossRule sellStopLossRule = new StopLossRule(closePrice, DecimalNum.valueOf("2"));

        ContractRule buyEntryRule = new ContractRule(buyRule, true);
        ContractRule takeBuyProfitExitRule = new ContractRule(takeBuyProfitRule, false);
        ContractRule buyStopLossExitRule = new ContractRule(buyStopLossRule, false);
        ContractRule buyExitRule = (ContractRule) takeBuyProfitExitRule.or(buyStopLossExitRule);
        ContractRule sellEntryRule = new ContractRule(sellRule, false);
        ContractRule takeSellProfitExitRule = new ContractRule(takeSellProfitRule, true);
        ContractRule sellStopLossExitRule = new ContractRule(sellStopLossRule, true);
        ContractRule sellExitRule = (ContractRule) takeSellProfitExitRule.or(sellStopLossExitRule);
        ContractStrategy strategy = new ContractStrategy(name, buyEntryRule, buyExitRule, sellEntryRule, sellExitRule);
        return strategy;
    }
}
